package com.xhai.security.wrapper;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xhai.common.constant.RequestConstants;
import com.xhai.common.exception.ServiceException;
import com.xhai.common.utils.classes.StringUtils;
import com.xhai.common.utils.encrypt.DecryptUtils;
import com.xhai.common.utils.i18n.MessageUtils;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.security.PrivateKey;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xhai
 * @description 解密请求包装类
 * @date 2025/6/7
 */
@Slf4j
public class DecryptedRequestWrapper extends HttpServletRequestWrapper {
    // RequestParam参数
    private Map<String, String[]> decryptedParameters;

    // RequestBody
    private byte[] body;

    private String frontendDecryptKey;

    public DecryptedRequestWrapper(HttpServletRequest request, String frontendDecryptKey) {
        super(request);
        try {
            this.decryptedParameters = new HashMap<>(request.getParameterMap());
            this.frontendDecryptKey = frontendDecryptKey;
            this.body = request.getInputStream().readAllBytes();
            if (body != null && body.length > 0) {
                decryptLoginForm();
            }
        } catch (Exception e) {
            log.error("Decrypt request failed：\n{}", e.getMessage());
        }
    }

    /**
     * 解密请求中的username和password
     */
    private void decryptLoginForm() {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            Map<String, Object> bodyParamMap = objectMapper.readValue(this.body, Map.class);

            // 获取对称加密密钥参数
            String aesSecretKey = (String) bodyParamMap.get(RequestConstants.REQUEST_PARAM_LOGIN_AES_SECRET_KEY);
            // 非对称加密私钥
            PrivateKey frontendPrivateKey = DecryptUtils.getRSAPrivateKeyFromBase64(frontendDecryptKey);
            if (!StringUtils.isEmpty(aesSecretKey)) {
                String decryptedAesPrivateKey = DecryptUtils.decryptRSA(frontendPrivateKey, aesSecretKey);
                // 重新设置请求参数
                // 解密处理
                for (String param : bodyParamMap.keySet()) {
                    String paramValue = bodyParamMap.get(param).toString();
                    String decryptedParamValue = DecryptUtils.decryptAES(decryptedAesPrivateKey, paramValue);
                    bodyParamMap.put(param, decryptedParamValue);
                }
            }

            this.body = objectMapper.writeValueAsString(bodyParamMap).getBytes();

        } catch (Exception e) {
            log.error("解密登录表单信息失败：", e);
            throw new ServiceException(MessageUtils.message("login.decrypt.error"));
        }
    }

    @Override
    public String getParameter(String name) {
        String[] values = decryptedParameters.get(name);
        return values != null && values.length > 0 ? values[0] : null;
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        return decryptedParameters;
    }

    @Override
    public Enumeration<String> getParameterNames() {
        return Collections.enumeration(decryptedParameters.keySet());
    }

    @Override
    public String[] getParameterValues(String name) {
        return decryptedParameters.get(name);
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return byteArrayInputStream.available() == 0;
            }

            @Override
            public boolean isReady() {
                return true;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
                throw new UnsupportedOperationException();
            }

            @Override
            public int read() {
                return byteArrayInputStream.read();
            }
        };
    }
}
